package com.danciyixue.boot.dcyx.service.impl;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.danciyixue.boot.core.security.util.SecurityUtils;
import com.danciyixue.boot.dcyx.mapper.TaskAssignmentItemMapper;
import com.danciyixue.boot.dcyx.mapper.TaskAssignmentMapper;
import com.danciyixue.boot.dcyx.model.entity.TaskAssignment;
import com.danciyixue.boot.dcyx.model.entity.TaskAssignmentItem;
import com.danciyixue.boot.dcyx.model.entity.UnitStudyStatus;
import com.danciyixue.boot.dcyx.model.form.TaskAssignForm;
import com.danciyixue.boot.dcyx.model.form.TaskAssignItemForm;
import com.danciyixue.boot.dcyx.model.query.TaskMatrixQuery;
import com.danciyixue.boot.dcyx.model.vo.TaskItemVO;
import com.danciyixue.boot.dcyx.service.TaskAssignmentService;
import com.danciyixue.boot.dcyx.service.UnitStudyStatusService;
import com.danciyixue.boot.dcyx.service.TestRecordsService;
import com.danciyixue.boot.dcyx.mapper.TestRecordsMapper;
import com.danciyixue.boot.dcyx.model.entity.TestRecords;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Service
@DS("dcyx")
@RequiredArgsConstructor
public class TaskAssignmentServiceImpl extends ServiceImpl<TaskAssignmentMapper, TaskAssignment> implements TaskAssignmentService {

    private final TaskAssignmentItemMapper itemMapper;
    private final UnitStudyStatusService unitStudyStatusService;
    private final TestRecordsService testRecordsService;
    private final TestRecordsMapper testRecordsMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean assign(TaskAssignForm form) {
        Long teacherId = SecurityUtils.getUserId();
        Objects.requireNonNull(teacherId, "未登录");

        // 1) upsert 主任务
        TaskAssignment assignment = this.lambdaQuery()
                .eq(TaskAssignment::getTeacherId, teacherId)
                .eq(TaskAssignment::getStudentId, form.getStudentId())
                .eq(TaskAssignment::getTargetDate, form.getTargetDate())
                .one();
        if (assignment == null) {
            assignment = new TaskAssignment();
            assignment.setTeacherId(teacherId);
            assignment.setStudentId(form.getStudentId());
            assignment.setTargetDate(form.getTargetDate());
            assignment.setStatus(0);
            this.save(assignment);
        }

        // 2) 子项幂等新增（限定在当前教师的 assignment 作用域内：assignmentId+unitId 唯一）
        for (TaskAssignItemForm i : form.getItems()) {
            Long exists = itemMapper.selectCount(new LambdaQueryWrapper<TaskAssignmentItem>()
                    .eq(TaskAssignmentItem::getAssignmentId, assignment.getId())
                    .eq(TaskAssignmentItem::getUnitId, i.getUnitId())
            );
            if (exists != null && exists > 0) continue;

            TaskAssignmentItem item = new TaskAssignmentItem();
            item.setAssignmentId(assignment.getId());
            item.setStudentId(form.getStudentId());
            item.setTargetDate(form.getTargetDate());
            item.setSeriesId(i.getSeriesId());
            item.setProgramId(i.getProgramId());
            item.setUnitId(i.getUnitId());
            item.setPassScore(i.getPassScore());
            item.setStatus(0);
            item.setAttemptCount(0);
            itemMapper.insert(item);
        }

        recalcAssignmentStatus(assignment.getId());
        return true;
    }

    @Override
    public void recalcAssignmentStatus(Long assignmentId) {
        List<TaskAssignmentItem> items = itemMapper.selectList(new LambdaQueryWrapper<TaskAssignmentItem>()
                .eq(TaskAssignmentItem::getAssignmentId, assignmentId));
        if (items.isEmpty()) {
            this.lambdaUpdate().eq(TaskAssignment::getId, assignmentId).set(TaskAssignment::getStatus, 0).update();
            return;
        }
        long done = items.stream().filter(i -> i.getStatus() != null && i.getStatus() == 1).count();
        int status = (done == 0) ? 0 : (done == items.size() ? 2 : 1);
        this.lambdaUpdate().eq(TaskAssignment::getId, assignmentId).set(TaskAssignment::getStatus, status).update();
    }

    @Override
    public List<TaskItemVO> getTodayTasksForCurrentStudent() {
        Long studentId = SecurityUtils.getUserId();
        LocalDate today = LocalDate.now();
        List<TaskAssignmentItem> items = itemMapper.selectList(new LambdaQueryWrapper<TaskAssignmentItem>()
                .eq(TaskAssignmentItem::getStudentId, studentId)
                .eq(TaskAssignmentItem::getTargetDate, today));
        return items.stream().map(this::toVOWithCanTest).collect(Collectors.toList());
    }

    @Override
    public boolean hasTodayPendingForCurrentStudent() {
        Long studentId = SecurityUtils.getUserId();
        LocalDate today = LocalDate.now();
        Long cnt = itemMapper.selectCount(new LambdaQueryWrapper<TaskAssignmentItem>()
                .eq(TaskAssignmentItem::getStudentId, studentId)
                .eq(TaskAssignmentItem::getTargetDate, today)
                .eq(TaskAssignmentItem::getStatus, 0));
        return cnt != null && cnt > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean refreshItemForCurrentStudent(Long itemId) {
        Long studentId = SecurityUtils.getUserId();
        TaskAssignmentItem item = itemMapper.selectById(itemId);
        if (item == null || !Objects.equals(item.getStudentId(), studentId)) {
            return false;
        }

        // 规则：以单元测试(TestRecords.type=2) 且 时间在任务创建之后 为准
        // 这里通过 TestRecordsService 的列表接口与UnitStudyStatus 辅助 canTest 判定
        Integer score = fetchLatestUnitTestScore(studentId, item.getUnitId(), item.getCreateTime());
        boolean ok = score != null && item.getPassScore() != null && score >= item.getPassScore();
        if (ok) {
            TaskAssignmentItem upd = new TaskAssignmentItem();
            upd.setId(item.getId());
            upd.setStatus(1);
            upd.setScore(score);
            upd.setCompletedAt(LocalDateTime.now());
            itemMapper.updateById(upd);
            // 回写主任务状态
            recalcAssignmentStatus(item.getAssignmentId());
        }
        return ok;
    }

    @Override
    public Map<Long, Map<LocalDate, List<TaskAssignmentItem>>> getMatrix(TaskMatrixQuery query) {
        Long teacherId = SecurityUtils.getUserId();
        LocalDate start = query.getDateStart();
        LocalDate end = query.getDateEnd();
        LambdaQueryWrapper<TaskAssignment> aw = new LambdaQueryWrapper<TaskAssignment>()
                .eq(TaskAssignment::getTeacherId, teacherId);
        if (start != null) aw.ge(TaskAssignment::getTargetDate, start);
        if (end != null) aw.le(TaskAssignment::getTargetDate, end);

        List<TaskAssignment> assignments = this.list(aw);
        if (assignments.isEmpty()) return Collections.emptyMap();

        Map<Long, List<TaskAssignment>> byStudent = assignments.stream().collect(Collectors.groupingBy(TaskAssignment::getStudentId));
        Map<Long, Map<LocalDate, List<TaskAssignmentItem>>> result = new HashMap<>();
        for (Map.Entry<Long, List<TaskAssignment>> e : byStudent.entrySet()) {
            Long studentId = e.getKey();
            Map<LocalDate, List<TaskAssignmentItem>> dayMap = new HashMap<>();
            for (TaskAssignment a : e.getValue()) {
                List<TaskAssignmentItem> items = itemMapper.selectList(new LambdaQueryWrapper<TaskAssignmentItem>()
                        .eq(TaskAssignmentItem::getAssignmentId, a.getId()));
                dayMap.put(a.getTargetDate(), items);
            }
            result.put(studentId, dayMap);
        }
        return result;
    }

    @Override
    public boolean updateItemPassScore(Long itemId, Integer passScore) {
        TaskAssignmentItem item = itemMapper.selectById(itemId);
        if (item == null) return false;
        TaskAssignmentItem upd = new TaskAssignmentItem();
        upd.setId(itemId);
        upd.setPassScore(passScore);
        int rows = itemMapper.updateById(upd);
        recalcAssignmentStatus(item.getAssignmentId());
        return rows > 0;
    }

    @Override
    public boolean deleteItem(Long itemId) {
        TaskAssignmentItem item = itemMapper.selectById(itemId);
        if (item == null) return false;
        int rows = itemMapper.deleteById(itemId);
        recalcAssignmentStatus(item.getAssignmentId());
        return rows > 0;
    }

    @Override
    public List<TaskAssignmentItem> listItemsByDate(LocalDate targetDate) {
        Long teacherId = SecurityUtils.getUserId();
        // 先找出当天该教师的主任务，再取子项
        List<TaskAssignment> assignments = this.list(new LambdaQueryWrapper<TaskAssignment>()
                .eq(TaskAssignment::getTeacherId, teacherId)
                .eq(TaskAssignment::getTargetDate, targetDate));
        if (assignments.isEmpty()) return Collections.emptyList();
        List<Long> ids = assignments.stream().map(TaskAssignment::getId).toList();
        return itemMapper.selectList(new LambdaQueryWrapper<TaskAssignmentItem>()
                .in(TaskAssignmentItem::getAssignmentId, ids)
                .orderByAsc(TaskAssignmentItem::getStudentId, TaskAssignmentItem::getUnitId));
    }

    private TaskItemVO toVOWithCanTest(TaskAssignmentItem item) {
        TaskItemVO vo = new TaskItemVO();
        vo.setId(item.getId());
        vo.setSeriesId(item.getSeriesId());
        vo.setProgramId(item.getProgramId());
        vo.setUnitId(item.getUnitId());
        vo.setPassScore(item.getPassScore());
        vo.setStatus(item.getStatus());
        vo.setScore(item.getScore());

        // canTest：任一学习类型完成 且 完成时间在子项创建之后
        boolean learned = hasAnyLearningCompletedAfter(item.getStudentId(), item.getUnitId(), item.getCreateTime());
        vo.setCanTest(learned);
        return vo;
    }

    private boolean hasAnyLearningCompletedAfter(Long studentId, Long unitId, LocalDateTime since) {
        UnitStudyStatus status = unitStudyStatusService.getOne(new LambdaQueryWrapper<UnitStudyStatus>()
                .eq(UnitStudyStatus::getUserId, studentId)
                .eq(UnitStudyStatus::getUnitId, unitId));
        if (status == null) return false;
        // 无法从表面字段得知完成时间，这里仅判断是否完成（YAGNI：简化为只要完成过即允许测试）
        return (isCompleted(status.getMemoryCompleted())
                || isCompleted(status.getDictationCompleted())
                || isCompleted(status.getWritingCompleted()));
    }

    private boolean isCompleted(Integer v) {
        return v != null && v == 1;
    }

    private Integer fetchLatestUnitTestScore(Long studentId, Long unitId, LocalDateTime since) {
        List<TestRecords> records = testRecordsMapper.selectList(new LambdaQueryWrapper<TestRecords>()
                .eq(TestRecords::getUserId, studentId)
                .eq(TestRecords::getUnitId, unitId)
                .eq(TestRecords::getType, 2)
                .ge(since != null, TestRecords::getCreateTime, since)
                .orderByDesc(TestRecords::getCreateTime)
        );
        if (records == null || records.isEmpty()) {
            return null;
        }
        return records.get(0).getScore();
    }
}
